﻿using LF.Application.Helpers;
using LF.Shared.Dtos.Input;
using LF.Shared.Dtos.Out;
using Microsoft.AspNetCore.Mvc;
using Volo.Abp.ObjectMapping;
using LF.Domain.Services;
using Microsoft.AspNetCore.Http;
using LF.Application.Extend;
using Microsoft.AspNetCore.Authorization;
using System.IO;
using LF.Domain.Entities;

namespace LF.Application.Services.Iml
{
    [Authorize]
    [ApiExplorerSettings(GroupName = SwaggerGroup.Sys)]
    public class FileService : BaseService, IFileService
    {
        IAppManagerService _appManager;
        IHttpContextAccessor _accessor;
        object moving = true;
        public FileService(IObjectMapper<LFModule> mapper, IAppManagerService appManager, IHttpContextAccessor accessor,
            IGlobalManagerService globalManager) : base(mapper, globalManager)
        {
            _appManager = appManager;
            _accessor = accessor;
        }

        public Result<FileOut> Upload(FileInput file)
        {
            if (file.Md5.IsNullOrEmpty() || file.CurrentChunk == 0)
            {
                return Error(new FileOut { Exists = false, Msg = "非法上传" });
            }
            const string ext = ".temp";
            var toPath = Path.Combine(LFConfig.FilePath.Path, file.Md5);

            //文件已上传
            if (Directory.Exists(toPath))
            {
                return Ok(new FileOut { Exists = true });
            }

            var path = Path.Combine(LFConfig.FilePath.Temp, file.Md5);
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);

            var filePath = Path.Combine(path, file.CurrentChunk.ToString().PadLeft(file.TotalChunk.ToString().Length, '0'));
            //分片已上传，返回已上传片数
            if (File.Exists(filePath))
            {
                var lastChunk = Directory.GetFiles(path).Count(p => !p.EndsWith(ext));
                return Ok(new FileOut { CurrentSuccess = true, LastChunk = lastChunk });
            }
            //保存临时文件
            var temp = filePath + ext;
            lock (moving)
            {
                using (var stream = new FileStream(temp, FileMode.Create, FileAccess.Write, FileShare.Read, file.Data.Length))
                    stream.Write(file.Data, 0, file.Data.Length);
                //写入成功，重命名为正式文件
                File.Move(temp, filePath);
                //最后一片已上传
                if (file.TotalChunk == file.CurrentChunk)
                {
                    if (!Directory.Exists(LFConfig.FilePath.Path))
                    {
                        Directory.CreateDirectory(LFConfig.FilePath.Path);
                    }
                    //临时目录转移至正式目录
                    Directory.Move(path, toPath);
                }
            }
            _appManager.Insert(new Domain.Entities.SysFile { Md5 = file.Md5, Name = file.Name, UserId = _accessor.HttpContext!.User.GetUserId() });
            return Ok(new FileOut { CurrentSuccess = true });
        }



        public FileContentResult? Download(string md5)
        {
            var stream = FileHelper.Get(md5);
            if (stream == null) return null;
            var sysfile = _appManager.GetFile(md5);
            var contentType = "application/octet-stream";
            if (sysfile != null)
            {
                var ext = Path.GetExtension(sysfile.Name).ToLower();
                switch (ext)
                {
                    case ".pdf":
                        contentType = "application/pdf";
                        break;
                    case ".png":
                        contentType = "application/x-png";
                        break;
                    case ".jpg":
                    case ".jpeg":
                        contentType = "application/x-jpg";
                        break;
                    case ".mp4":
                        contentType = "video/mpeg4";
                        break;
                    case ".doc":
                    case ".docx":
                        contentType = "application/msword";
                        break;
                    case ".xls":
                    case ".xlsx":
                        contentType = "application/vnd.ms-excel";
                        break;
                    case ".ppt":
                    case ".pptx":
                        contentType = "application/vnd.ms-powerpoint";
                        break;
                    case ".zip":
                        contentType = "application/zip";
                        break;
                    case ".rar":
                        contentType = "application/x-rar-compressed";
                        break;
                }
            }

            using (stream)
            {
                if (stream == null) return new FileContentResult(new byte[0], "application/octet-stream");
                byte[] bytes = new byte[stream.Length];
                stream.Read(bytes, 0, bytes.Length);
                var file = new FileContentResult(bytes, contentType);
                file.FileDownloadName = sysfile?.Name;
                return file;
            }
        }

        public Result<FileContentResult> ? DownloadEx(string md5)
        {
            var stream = FileHelper.Get(md5);
            if (stream == null) return null;
            var sysfile = _appManager.GetFile(md5);
            var contentType = "application/octet-stream";
            if (sysfile != null)
            {
                var ext = Path.GetExtension(sysfile.Name).ToLower();
                switch (ext)
                {
                    case ".pdf":
                        contentType = "application/pdf";
                        break;
                    case ".png":
                        contentType = "application/x-png";
                        break;
                    case ".jpg":
                    case ".jpeg":
                        contentType = "application/x-jpg";
                        break;
                    case ".mp4":
                        contentType = "video/mpeg4";
                        break;
                    case ".doc":
                    case ".docx":
                        contentType = "application/msword";
                        break;
                    case ".xls":
                    case ".xlsx":
                        contentType = "application/vnd.ms-excel";
                        break;
                    case ".ppt":
                    case ".pptx":
                        contentType = "application/vnd.ms-powerpoint";
                        break;
                    case ".zip":
                        contentType = "application/zip";
                        break;
                    case ".rar":
                        contentType = "application/x-rar-compressed";
                        break;
                }
            }

            using (stream)
            {
                if (stream == null) return Ok(new FileContentResult(new byte[0], "application/octet-stream"));
                byte[] bytes = new byte[stream.Length];
                stream.Read(bytes, 0, bytes.Length);
                var file = new FileContentResult(bytes, contentType);
                file.FileDownloadName = sysfile?.Name;
                return Ok(file);
            }
        }

        [AllowAnonymous]
        public FileContentResult? GetFirstFrame(string md5)
        {
            var sysfile = _appManager.GetFile(md5);

            var frame = FileHelper.FirstFrame(md5);
            if (string.IsNullOrEmpty(frame))
            {
                return new FileContentResult(new byte[0], "application/octet-stream");
            }
            var file = new FileContentResult(File.ReadAllBytes(frame), "application/x-png")
            {
                FileDownloadName = sysfile.Name.Replace(Path.GetExtension(sysfile.Name), ".png")
            };
            return file;
        }
        [AllowAnonymous]
        [HttpGet]
        public FileContentResult? Download2(string md5)
        {
            return Download(md5);
        }

        public Result GetFileName(string md5)
        {
            var file = _globalManager.Get<SysFile>(p=>p.Md5 == md5);
            return Ok(file?.Name ?? "");
        }

        /// <summary>
        /// 前端直接下载文件
        /// </summary>
        /// <param name="md5">文件md5</param>
        /// <returns>文件流</returns>
        [AllowAnonymous]
        [HttpGet]
        public IActionResult DirectDownload(string md5)
        {
            var stream = FileHelper.Get(md5);
            if (stream == null) return new NotFoundObjectResult("文件不存在");
            
            var sysfile = _appManager.GetFile(md5);
            var fileName = sysfile?.Name ?? md5;
            var contentType = "application/octet-stream";
            
            if (sysfile != null)
            {
                var ext = Path.GetExtension(fileName).ToLower();
                switch (ext)
                {
                    case ".pdf":
                        contentType = "application/pdf";
                        break;
                    case ".png":
                        contentType = "application/x-png";
                        break;
                    case ".jpg":
                    case ".jpeg":
                        contentType = "application/x-jpg";
                        break;
                    case ".mp4":
                        contentType = "video/mpeg4";
                        break;
                    case ".doc":
                    case ".docx":
                        contentType = "application/msword";
                        break;
                    case ".xls":
                    case ".xlsx":
                        contentType = "application/vnd.ms-excel";
                        break;
                    case ".ppt":
                    case ".pptx":
                        contentType = "application/vnd.ms-powerpoint";
                        break;
                    case ".zip":
                        contentType = "application/zip";
                        break;
                    case ".rar":
                        contentType = "application/x-rar-compressed";
                        break;
                }
            }
            
            // 设置响应头，使浏览器直接下载文件而不是打开
            _accessor.HttpContext!.Response.Headers.Append("Content-Disposition", $"attachment; filename=\"{Uri.EscapeDataString(fileName)}\"");
            
            return new FileStreamResult(stream, contentType) { FileDownloadName = fileName };
        }
    }
}
